/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSG_IO_UTILS
#define OSG_IO_UTILS 1

#include <ostream>
#include <istream>
#include <sstream>

#include <osg/Vec4d>
#include <osg/Vec4ub>
#include <osg/Vec2b>
#include <osg/Vec3b>
#include <osg/Vec4b>
#include <osg/Vec2s>
#include <osg/Vec3s>
#include <osg/Vec4s>
#include <osg/Vec2i>
#include <osg/Vec3i>
#include <osg/Vec4i>
#include <osg/Matrixf>
#include <osg/Matrixd>
#include <osg/Plane>

namespace osg {


/** Convinience class for building std::string using stringstream.
  * Usage:
  *    MakeString str;
  *    std::string s = str<<"Mix strings with numbers "<<0" ;
  *    std::string s2 = str.clear()<<"and other classes such as ("<<osg::Vec3(0.0,1.0,3.0)<<)" ; */
class MakeString
{
    public:
        MakeString() {}

        std::stringstream sstream;

        template<typename T>
        MakeString& operator << (const T& t)
        {
            sstream << t;
            return *this;
        }

        MakeString& operator << (std::ostream& (*fun)(std::ostream&))
        {
            sstream << fun;
            return *this;
        }

        inline MakeString& clear() { sstream.str("") ; return *this; }

        inline operator std::string () const { return sstream.str(); }

        inline std::string str() const { return sstream.str(); }
};



inline std::ostream& operator << (std::ostream& output, const MakeString& str) { output << str.str(); return output; }

//////////////////////////////////////////////////////////////////////////
// Vec2f streaming operators
inline std::ostream& operator << (std::ostream& output, const Vec2f& vec)
{
    output << vec._v[0] << " " << vec._v[1];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec2f& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec2d steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec2d& vec)
{
    output << vec._v[0] << " " << vec._v[1];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec2d& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec3f steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec3f& vec)
{
    output << vec._v[0] << " "
           << vec._v[1] << " "
           << vec._v[2];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec3f& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1] >> std::ws >> vec._v[2];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Vec3d steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec3d& vec)
{
    output << vec._v[0] << " "
           << vec._v[1] << " "
           << vec._v[2];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec3d& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1] >> std::ws >> vec._v[2];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Vec3f steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4f& vec)
{
    output  << vec._v[0] << " "
            << vec._v[1] << " "
            << vec._v[2] << " "
            << vec._v[3];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec4f& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}



//////////////////////////////////////////////////////////////////////////
// Vec4d steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4d& vec)
{
    output << vec._v[0] << " "
           << vec._v[1] << " "
           << vec._v[2] << " "
           << vec._v[3];
    return output;     // to enable cascading
}
inline std::istream& operator >> (std::istream& input, Vec4d& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Vec2b steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec2b& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec2b& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec3b steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec3b& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1] << " "
           << (int)vec._v[2];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec3b& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1] >> std::ws >> vec._v[2];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec4b steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4b& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1] << " "
           << (int)vec._v[2] << " "
           << (int)vec._v[3];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec4b& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Vec2s steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec2s& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec2s& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec3s steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec3s& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1] << " "
           << (int)vec._v[2];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec3s& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1] >> std::ws >> vec._v[2];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec4s steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4s& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1] << " "
           << (int)vec._v[2] << " "
           << (int)vec._v[3];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec4s& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}



//////////////////////////////////////////////////////////////////////////
// Vec2i steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec2i& vec)
{
    output << vec._v[0] << " "
           << vec._v[1];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec2i& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec3i steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec3i& vec)
{
    output << vec._v[0] << " "
           << vec._v[1] << " "
           << vec._v[2];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec3i& vec)
{
    input >> vec._v[0] >> std::ws >> vec._v[1] >> std::ws >> vec._v[2];
    return input;
}

//////////////////////////////////////////////////////////////////////////
// Vec4i steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4i& vec)
{
    output << vec._v[0] << " "
           << vec._v[1] << " "
           << vec._v[2] << " "
           << vec._v[3];
    return output; // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec4i& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Matrixf steaming operators.
inline std::ostream& operator<< (std::ostream& os, const Matrixf& m )
{
    os << "{"<<std::endl;
    for(int row=0; row<4; ++row) {
        os << "\t";
        for(int col=0; col<4; ++col)
            os << m(row,col) << " ";
        os << std::endl;
    }
    os << "}" << std::endl;
    return os;
}


//////////////////////////////////////////////////////////////////////////
// Matrixd steaming operators.
inline std::ostream& operator<< (std::ostream& os, const Matrixd& m )
{
    os << "{"<<std::endl;
    for(int row=0; row<4; ++row) {
        os << "\t";
        for(int col=0; col<4; ++col)
            os << m(row,col) << " ";
        os << std::endl;
    }
    os << "}" << std::endl;
    return os;
}

//////////////////////////////////////////////////////////////////////////
// Vec4ub steaming operators.
inline std::ostream& operator << (std::ostream& output, const Vec4ub& vec)
{
    output << (int)vec._v[0] << " "
           << (int)vec._v[1] << " "
           << (int)vec._v[2] << " "
           << (int)vec._v[3];
    return output;         // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Vec4ub& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}


//////////////////////////////////////////////////////////////////////////
// Quat steaming operators.
inline std::ostream& operator << (std::ostream& output, const Quat& vec)
{
    output << vec._v[0] << " "
       << vec._v[1] << " "
       << vec._v[2] << " "
       << vec._v[3];
    return output;     // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Quat& vec)
{
    input >> vec._v[0] >> std::ws
          >> vec._v[1] >> std::ws
          >> vec._v[2] >> std::ws
          >> vec._v[3];
    return input;
}



//////////////////////////////////////////////////////////////////////////
// Plane steaming operators.
inline std::ostream& operator << (std::ostream& output, const Plane& pl)
{
    output << pl[0] << " "
           << pl[1] << " "
           << pl[2] << " "
           << pl[3];
    return output;         // to enable cascading
}

inline std::istream& operator >> (std::istream& input, Plane& vec)
{
    input >> vec[0] >> std::ws
          >> vec[1] >> std::ws
          >> vec[2] >> std::ws
          >> vec[3];
    return input;
}

}    // end of namespace osg
#endif
